package ace.module.mail.address.core.impl.service.impl;

import ace.cmp.core.model.PageResultDto;
import ace.cmp.id.generator.api.LongIdGenerator;
import ace.cmp.spring.data.jdbc.querydsl.core.converter.PageConverter;
import ace.cmp.util.AceEnumUtils;
import ace.module.common.api.model.input.TenantAndAppTypeInput;
import ace.module.common.api.model.input.TenantInput;
import ace.module.common.api.model.input.TenantPageInput;
import ace.module.mail.address.api.constant.MailAddressConstant;
import ace.module.mail.address.api.enums.MadMailAddressTypeEnum;
import ace.module.mail.address.api.model.dto.MadMailAddressDto;
import ace.module.mail.address.api.model.input.mailaddress.MadMailAddressAddInput;
import ace.module.mail.address.api.model.input.mailaddress.MadMailAddressAddItemInput;
import ace.module.mail.address.api.model.input.mailaddress.MadMailAddressAdminFilterInput;
import ace.module.mail.address.api.model.input.mailaddress.MadMailAddressFilterInput;
import ace.module.mail.address.api.model.input.mailaddress.MadMailAddressModifyInput;
import ace.module.mail.address.api.model.input.mailaddress.MadMailAddressModifyItemInput;
import ace.module.mail.address.api.model.input.mailaddress.MadMailAddressSearchInput;
import ace.module.mail.address.core.impl.dao.entity.MadApplication;
import ace.module.mail.address.core.impl.manager.MadApplicationManager;
import ace.module.mail.address.core.impl.manager.MadMailAddressManager;
import ace.module.mail.address.core.impl.service.MadMailAddressService;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

/**
 * .
 *
 * @author Caspar
 */
@Slf4j
@AllArgsConstructor
@Component
public class MadMailAddressServiceImpl implements MadMailAddressService {

  private final MadMailAddressManager madMailAddressManager;
  private final MadApplicationManager madApplicationManager;
  private final PageConverter pageConverter;
  private final LongIdGenerator idGenerator;

  @Override
  public PageResultDto<MadMailAddressDto> search(MadMailAddressSearchInput input) {
    MadApplication madApplication = this.madApplicationManager.getByOutTypeAndOutId(
        input.getAppOutInfo().getOutType(), input.getAppOutInfo().getOutId());
    if (Objects.isNull(madApplication)) {
      return new PageResultDto<>();
    }

    List<Long> accountIds = new ArrayList<>();
    Optional.ofNullable(input)
        .map(MadMailAddressSearchInput::getFilter)
        .map(MadMailAddressAdminFilterInput::getAccountId)
        .ifPresent(accountId -> accountIds.add(accountId));

    MadMailAddressFilterInput filter = MadMailAddressFilterInput.builder()
        .madAppId(madApplication.getId())
        .contactPhone(
            Optional.ofNullable(input)
                .map(MadMailAddressSearchInput::getFilter)
                .map(MadMailAddressAdminFilterInput::getContactPhone)
                .orElse(null)
        )
        .contacts(
            Optional.ofNullable(input)
                .map(MadMailAddressSearchInput::getFilter)
                .map(MadMailAddressAdminFilterInput::getContacts)
                .orElse(null)
        )
        .type(
            Optional.ofNullable(input)
                .map(MadMailAddressSearchInput::getFilter)
                .map(MadMailAddressAdminFilterInput::getType)
                .orElse(null)
        )
        .accountIds(accountIds)
        .build();
    Pageable pageable = pageConverter.toPageRequest(input.getPage());
    return madMailAddressManager.search(filter, pageable);
  }

  @Transactional(rollbackFor = Exception.class)
  @Override
  public Long addByAppOutId(MadMailAddressAddInput input) {
    MadApplication madApplication = this.madApplicationManager.getAndCheckByOutTypeAndOutId(
        input.getAppOutInfo().getOutType(), input.getAppOutInfo().getOutId());

    MadMailAddressTypeEnum typeEnum = AceEnumUtils.getEnum(MadMailAddressTypeEnum.class, input.getAddress().getType());
    MadMailAddressDto addressDto = new MadMailAddressDto();
    BeanUtils.copyProperties(input.getAddress(), addressDto);
    Long id = idGenerator.get();
    boolean isDefault = Optional.of(addressDto)
        .map(MadMailAddressDto::getDefaultFlag)
        .orElse(id)
        .equals(MailAddressConstant.MAIL_ADDRESS_DEFAULT_FLAG_TRUE_VALUE);
    Long defaultFlag = isDefault ? MailAddressConstant.MAIL_ADDRESS_DEFAULT_FLAG_TRUE_VALUE : id;

    addressDto.setId(id);
    addressDto.setMadAppId(madApplication.getId());
    addressDto.setDefaultFlag(defaultFlag);

    if (isDefault) {
      this.madMailAddressManager.cancelDefault(
          madApplication.getId(),
          addressDto.getAccountId(),
          typeEnum);
    }
    this.madMailAddressManager.addDto(addressDto, false);
    return addressDto.getId();
  }

  @Transactional(rollbackFor = Exception.class)
  @Override
  public void modifyByAppOutId(MadMailAddressModifyInput input) {
    MadApplication madApplication = this.madApplicationManager.getAndCheckByOutTypeAndOutId(
        input.getAppOutInfo().getOutType(), input.getAppOutInfo().getOutId());

    MadMailAddressTypeEnum typeEnum = AceEnumUtils.getEnum(MadMailAddressTypeEnum.class,
        input.getAddress().getType());
    MadMailAddressDto addressDto = new MadMailAddressDto();
    BeanUtils.copyProperties(input.getAddress(), addressDto);
    Long id = addressDto.getId();
    boolean isDefault = Optional.of(addressDto)
        .map(MadMailAddressDto::getDefaultFlag)
        .orElse(id)
        .equals(MailAddressConstant.MAIL_ADDRESS_DEFAULT_FLAG_TRUE_VALUE);
    Long defaultFlag = isDefault ? MailAddressConstant.MAIL_ADDRESS_DEFAULT_FLAG_TRUE_VALUE : id;

    addressDto.setId(id);
    addressDto.setMadAppId(madApplication.getId());
    addressDto.setDefaultFlag(defaultFlag);

    if (isDefault) {
      this.madMailAddressManager.cancelDefault(
          madApplication.getId(),
          addressDto.getAccountId(),
          typeEnum);
    }
    this.madMailAddressManager.modifyDto(addressDto, false);
  }

  @Override
  public MadMailAddressDto getByTenantAndAppTypeAndId(TenantAndAppTypeInput<Long> input) {
    Long outId = input.getTenantId();
    String outType = input.getType();
    Long mailAddressId = input.getData();

    return this.madMailAddressManager.getDtoByOutIdAndOutTypeAndId(outId, outType, mailAddressId);
  }

  @Override
  public Page<MadMailAddressDto> adminSearchInMemberScope(TenantPageInput<MadMailAddressAdminFilterInput> tenantPageInput) {
    return null;
  }

  @Override
  public Long adminAddMemberScope(TenantInput<MadMailAddressAddItemInput> input) {
    return null;
  }

  @Override
  public void modify(TenantInput<MadMailAddressModifyItemInput> input) {

  }

  @Override
  public void remove(List<Long> ids) {
    this.madMailAddressManager.remove(ids);
  }

  @Override
  public MadMailAddressDto get(TenantInput<Long> input) {

    return null;
  }
}